using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
namespace DL.UIBinding
{
    
    //新实现的一套绑定方案
    public abstract class Context
    {
        public GameObject go;
        public int Index;

        //因为不是找的，所以要指定
        //还有一种就是在new的时候去实例化绑定这个model
        public void Init(GameObject parent, GameObject self, int index)
        {
            go = self;
            RefreshChange(index);
            go.transform.SetParent(parent.transform);
            go.transform.SetSiblingIndex(Index);
            Bind();
        }

        // //这样只适合使用了加载方案的行为，这样可以保证稳定加载到实例。但是还是需要指定父节点
        // protected Context()
        // {
        //     
        // }

        //绑定和解绑
        protected abstract void Bind();
        protected abstract void UnBind();

        //所属队列修改过
        public void RefreshChange(int index)
        {
            Index = index;
            go.name = this.GetType().Name + $"_{index}";
        }

        public virtual void Destroy()
        {
            UnBind();
            Object.DestroyImmediate(go);
        }
    }

    public class Collection<T> where T : Context
    {
        public static Func<string, GameObject> _Loader;

        private readonly List<T> m_Items = new List<T>();

        private Transform parent;

        private GameObject _prefab;

        public int Count => m_Items.Count;

        public Collection(Transform parent)
        {
            this.parent = parent;
            _prefab = Load.Inst.LoadUIPage(typeof(T).Name);
        }

        // 写 Add 和 Insert Remove 方法 
        public void Add(T item) => Insert(item, this.m_Items.Count);

        //具体的绑定由Mono类完成 
        public void Insert(T item, int index)
        {
            if (index < 0 || index >= this.m_Items.Count)
                index = this.m_Items.Count;
            //加载这样一个同名实例
            // TODO 接入YooAsset 
            GameObject go = Object.Instantiate(_prefab, parent);
            // GameObject go = _Loader(typeof(T).Name);
            //调用Init方法
            item.Init(parent.gameObject, go, index);
            this.m_Items.Insert(index,item);
            if (index + 1 != this.m_Items.Count)
            {
                Refresh(item.Index);
            }
        }

        public T GetItem(int index) => index < 0 || index >= this.m_Items.Count ? default(T) : this.m_Items[index];

        public void Remove(int index)
        {
            if (m_Items.Count <= index) return;
            var item = m_Items[index];
            m_Items.Remove(item);
            item.Destroy();
            Refresh(item.Index);
        }

        public void Remove(T item)
        {
            for (int index = 0; index < this.m_Items.Count; ++index)
            {
                if ((object)this.m_Items[index] == (object)item)
                {
                    this.Remove(index);
                    break;
                }
            }
        }

        private void Refresh(int index = 0)
        {
            for (int i = index; i < m_Items.Count; i++)
            {
                var item = GetItem(i);
                item.RefreshChange(i);
            }
        }
    }
}